home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 051-075 / disk_075 / copy / cp.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  11KB  |  507 lines

  1. /* Cp:  A replacement for AmigaDos Copy that does not modify the date
  2.  *      by Jeff Lydiatt
  3.  *      Vancouver, Canada.
  4.  *
  5.  * Features:
  6.  *   1) Handles all functions of AmigaDos copy, including the All switch.
  7.  *   2) Regular expression pattern matching that handles the AmigaDos'
  8.  *       pattern matching characters "#?|%'()".
  9.  *   3) This copy keeps the date of the copied file!
  10.  *   4) Uses a 32K buffer which should speed up single disk copies.
  11.  *   5) In "Cp filex .", the "." is taken to mean the current directory.
  12.  *
  13.  * Created: 07May87
  14.  *
  15.  * Cp has been compiled and tested under Aztec v3.40a with patch v3
  16.  * applied.  The 16 bit integer and small code, small data option is
  17.  * used in compiling and linking all modules.
  18.  *
  19.  * Maintenance Notes:
  20.  *  17May87 - Version 1.0 Released.
  21.  *
  22.  */
  23.  
  24. /* 
  25.       Cp and the c source is freely redistributable for personal
  26.       non-commercial use.  Commercial rights are reserved by the
  27.       author.  Feel free to make any modifications or use any 
  28.       of the modules in other programs.  I encourage you to do so
  29.       and hope you will release the code so others can learn by it.
  30.  */
  31.  
  32. #include <stdio.h>
  33. #include <libraries/dos.h>
  34. #include <exec/memory.h>
  35. #include <functions.h>
  36.  
  37. #define BUFMAX 32768
  38. #define MAXSTR 127
  39.  
  40. extern int Enable_Abort;
  41. extern char *malloc();
  42. extern int CmplPat(), Match();
  43. extern long Chk_Abort();
  44.  
  45. /*--- A poor man's "printf" which avoids the overhead of printf ---*/
  46.  
  47. static void msg(str, parm)
  48. char    *str, *parm;
  49. {
  50.    register char *s;
  51.    register struct FileHandle *console;
  52.  
  53.    console = Output();
  54.    for ( s=str; *s; ++s )
  55.      {
  56.        if ( *s == '%' && *(s+1) == 's' )
  57.      {
  58.         (void)Write( console, str, (long)(s - str));
  59.         (void)Write( console, parm, (long)strlen(parm));
  60.         (void)Write( console, (char *)(s + 2), (long)strlen((char *)(s+2)));
  61.         break;
  62.      }
  63.      }
  64.  
  65.     if ( *s == '\0' )
  66.        (void)Write( console, str, (long)strlen(str));
  67. }
  68.   
  69. static void error( str, parm )
  70. char *str, *parm;
  71. {
  72.    msg( str, parm );
  73.    exit(NULL);
  74. }
  75.  
  76. static void useage(name)
  77. char *name;
  78. {
  79.     msg( "%s V1.0 buffered file copy by Jeff Lydiatt.  Usage:\n", name );
  80.     msg( "  %s [From] filein [To] fileout [All]\n", name );
  81.     msg( "  AmigaDos style pattern matching characters permitted in filein.\n" );
  82.     msg( "  Pattern matching characters not allowed in Fileout.\n\n" );
  83. }
  84.  
  85. /*-----------------------------------------------------------*/
  86. /*        Parse the command string             */
  87. /*-----------------------------------------------------------*/
  88.  
  89. static int toupper(c)
  90. register char c;
  91. {
  92.    if ( 'a' <= c && c <= 'z' )
  93.     return c + ('A' - 'a');
  94.    return c;
  95. }
  96.   
  97. /* Case-blind implementation of strcmp() */
  98.  
  99. static int blindcmp( s1, s2 )
  100. register char *s1, *s2;
  101. {
  102.      
  103.    while (*s1 && *s2)
  104.      {
  105.     if ( (toupper( *s1 )) == (toupper( *s2 )) )
  106.        {
  107.           ++s1; 
  108.           ++s2;
  109.        }
  110.         else
  111.        break;
  112.      }
  113.  
  114.    if ( toupper(*s1) == toupper(*s2) )
  115.       return 0; /* It's Equal */
  116.    else if ( toupper(*s1) > toupper(*s2) )
  117.       return 1;
  118.    else
  119.       return -1; 
  120. }
  121.  
  122. static void parsecmd(fparm, tparm, All, argc, argv)
  123. char *fparm, *tparm;
  124. register char *argv[];
  125. int *All, argc;
  126. {
  127.    int nextparm;
  128.    register char *parm;
  129.  
  130.    if ((argc < 2) || ( strcmp( argv[1], "?" ) == 0) )
  131.      {
  132.        useage( argv[0] );
  133.        exit( NULL );
  134.      }
  135.  
  136.    *All = FALSE;
  137.    nextparm = 1;
  138.    argc--;
  139.    fparm [0] = '\0';
  140.    tparm[0] = '\0';
  141.    while ( nextparm <= argc )
  142.      {
  143.     parm = argv[ nextparm ];
  144.     if ( (nextparm < argc) && (blindcmp( parm, "from" ) == 0) )
  145.       {
  146.         ++nextparm;
  147.         (void)strncpy( fparm, argv [nextparm], MAXSTR);
  148.       }
  149.     else if ( (nextparm < argc) && (blindcmp( parm, "to" ) == 0) )
  150.       {
  151.         ++nextparm;
  152.         (void)strncpy( tparm, argv [nextparm], MAXSTR );
  153.        }
  154.     else if ( (nextparm == argc) && (blindcmp( parm, "all") == 0) )
  155.         *All = TRUE;
  156.     else if ( fparm[0] == '\0' )
  157.        (void)strncpy( fparm, parm, MAXSTR );
  158.     else
  159.        (void)strncpy( tparm, parm, MAXSTR );
  160.     ++nextparm;
  161.      }
  162. }
  163.  
  164. /*--------------------------------------------------------------*/
  165. /*    Internal stack manipulation routines            */
  166. /*--------------------------------------------------------------*/
  167.  
  168. struct stackframe 
  169. {
  170.     struct stackframe *next;
  171.     char *strptr;
  172. };    
  173. static struct stackframe *Stackhead;
  174.  
  175. static void initstack()
  176. {
  177.     Stackhead = NULL;
  178. }
  179.  
  180. static int isempty()
  181. {
  182.    return Stackhead == NULL;
  183. }
  184.  
  185. /*--------------push a string on the stack------------------*/
  186.  
  187. static void push(str)    char *str; /* Push a string on the stack */
  188. {
  189.    register struct stackframe *p;
  190.    register char *s;
  191.  
  192.    if ( (p = (struct stackframe *)malloc(sizeof(struct stackframe))) == NULL
  193.       ||(s = malloc( strlen(str)+1 )) == NULL)
  194.       {
  195.     msg("Not enough memory\n");
  196.     return;
  197.       }
  198.  
  199.    strcpy( s, str );
  200.    p->next = Stackhead;
  201.    p->strptr = s;
  202.    Stackhead = p;
  203. }
  204.  
  205. /*---------pop the next string from the stack------------------*/
  206.  
  207. static void pop(str) char *str;
  208. {
  209.    register struct stackframe *p;
  210.  
  211.    if (isempty())
  212.     error("Can't happen: stack popped with nothing there\n");
  213.  
  214.    p = Stackhead;
  215.    strcpy( str, p->strptr );
  216.    free( p->strptr );
  217.    Stackhead = p->next;
  218.    free( p );
  219. }
  220.  
  221. /*--------------------------------------------------------------*/
  222. /*    Some handy path manipulation routines.            */
  223. /*--------------------------------------------------------------*/
  224.  
  225. /*------------separate path and pattern from str----------------*/
  226.  
  227. static char *getpath( path, pattern, str)
  228. char *path, *pattern, *str;
  229. {
  230.    register char *s1, *s2;
  231.    char *mark;
  232.  
  233.    mark = NULL;
  234.    for ( s1=str; *s1; ++s1)
  235.     if ( *s1 == ':' || *s1 == '/' )
  236.        mark = s1;
  237.  
  238.    if ( isdir(str) )
  239.      {
  240.     strcpy( path, str );
  241.     *pattern = '\0';
  242.      }
  243.    else if ( !mark )
  244.      {
  245.     strcpy( pattern, str );
  246.     *path = '\0';
  247.      }
  248.    else
  249.      {
  250.     s2 = path;
  251.     s1 = str;
  252.     while ( s1 < mark )
  253.        *s2++ = *s1++;
  254.     if ( *s1 == ':' )
  255.        *s2++ = *s1;
  256.     *s2 = '\0';
  257.     strcpy( pattern, (char*)( mark+1));
  258.      }
  259.  
  260.    return path;
  261. }
  262.  
  263. /*------return path from parent directory and member name-------*/
  264.  
  265. static char *makepath(path, parent, member)
  266. register char *path;
  267. char *member;
  268. register char *parent;
  269. {
  270.    register int len;
  271.  
  272.    strcpy( path, parent );
  273.    len = strlen( path );  
  274.    if ( len > 0 && *member )
  275.       if ( (path[len-1] != ':') && (path[len-1] != '/') )
  276.       strcat( path, "/" );
  277.    strcat( path, member );
  278.    return path;
  279. }
  280.  
  281. /*--- isdir: Returns 0 if NOT a directory, 1 otherwise. ---*/
  282.  
  283. static int isdir(filename)
  284. char    *filename;
  285. {
  286.     struct FileInfoBlock *f;
  287.     struct Lock *outlk;
  288.     int        result;
  289.  
  290.     result = 0;
  291.     outlk = (struct Lock *)Lock(filename,ACCESS_READ);
  292.     if (outlk) 
  293.       {
  294.         f = (struct FileInfoBlock *)
  295.          AllocMem((long)sizeof(struct FileInfoBlock), MEMF_CHIP);
  296.         if (f == 0) 
  297.         error("Unable to allocate space for FileInfoBlock!\n");
  298.         if (Examine(outlk,f))
  299.         if (f->fib_DirEntryType >= 0)
  300.         result = 1;
  301.         UnLock(outlk);
  302.         FreeMem((void *)f,(long) sizeof(struct FileInfoBlock));
  303.       }
  304.     return(result);
  305. }
  306.  
  307. static int iswild(pattern)
  308. register char *pattern;
  309. {
  310.    for (; *pattern; ++pattern )
  311.      {
  312.     switch( *pattern )
  313.      {
  314.        case '#':
  315.        case '?':
  316.        case '(':
  317.        case '%':
  318.        case '\'':
  319.        case '|': return 1;
  320.      }
  321.      }
  322.    return 0;
  323. }
  324.  
  325. static int cp(fpath, tpath, name )
  326. char *fpath, *tpath, *name;
  327. {
  328.    char fname[MAXSTR+1], tname[MAXSTR+1];
  329.    char *buffer;
  330.    long status, count, bufsize;
  331.    struct FileHandle *fin, *fout;
  332.    struct DateStamp date;
  333.  
  334.    (void)makepath( fname, fpath, name );
  335.  
  336.    if ( tpath[0] != '\0' && !isdir(tpath) )
  337.       strcpy( tname, tpath );
  338.    else
  339.       (void)makepath( tname, tpath, name );
  340.  
  341.    msg( "%s ==> ", fname ); msg( "%s\n", tname);
  342.    if ( (fin = Open( fname, MODE_OLDFILE )) == NULL )
  343.      {
  344.     msg( "Can't open %s for input.\n", fname );
  345.     return 1;
  346.      }
  347.    if ( (fout = Open( tname, MODE_NEWFILE )) == NULL )
  348.      {
  349.     msg( "Can't open %s for ouput.\n", tname );
  350.     Close( fin );
  351.     return 1;
  352.      }
  353.  
  354.    for ( bufsize = BUFMAX; bufsize > 2048; bufsize -= 2048 )
  355.       if ( (buffer = malloc( (unsigned int)bufsize)) != NULL )
  356.     break;
  357.  
  358.    if ( bufsize <= 2048 )
  359.       {
  360.     Close( fin );
  361.     Close( fout );
  362.     msg( "Not enough memory.\n" );
  363.     return 1;
  364.       }
  365.  
  366.     status = 1;
  367.     while( status > 0 && (count = Read( fin, buffer, bufsize )) == bufsize )
  368.       if ( Chk_Abort() )
  369.     status = -1;
  370.       else
  371.     status = Write( fout, buffer, count );
  372.  
  373.     if (status > 0 && count > 0 )
  374.     status = Write( fout, buffer, count );
  375.  
  376.     Close( fin );
  377.     Close( fout);
  378.     free( buffer );
  379.  
  380.     if ( status < 0 || count < 0 )
  381.       {
  382.     (void)DeleteFile( tname );
  383.     msg( "   %s [removed].\n", tname );
  384.     return 1;
  385.       }
  386.  
  387.     if ( getDate( fname, &date ))
  388.        (void)setDate( tname, &date );
  389.  
  390.     return 0;
  391. }
  392.  
  393. main(argc,argv)
  394. int    argc;
  395. char    *argv[];
  396. {
  397.    int  aux[MAXSTR+1];
  398.    char fparm[MAXSTR+1], tparm[MAXSTR+1];
  399.    char fpath[MAXSTR+1], tpath[MAXSTR+1];
  400.    char fparent[MAXSTR+1], dontSearch[MAXSTR+1];
  401.    char fpattern[MAXSTR+1];
  402.    char relpath[MAXSTR+1], junk[MAXSTR+1];
  403.    void *dirlock;
  404.    register struct FileInfoBlock *fileptr;
  405.    int All;
  406.  
  407.    Enable_Abort = 0;
  408.  
  409.    parsecmd( fparm, tparm, &All, argc, argv );
  410.    (void)getpath( fparent, fpattern, fparm );
  411.    if ( strcmp(tparm, ".") == 0 )
  412.       tparm[0] = '\0';
  413.  
  414.    /*--- Are the parms ok? --- */
  415.  
  416.    if ( iswild(fparent) )
  417.       error( "Regular expression not allowed in path: %s.\n", fparm );
  418.    if ( iswild(tparm) )
  419.       error( "Regular expression not allowed as output name.\n" );
  420.  
  421.    /*----- if it's just a single file copy, just do it and exit----*/
  422.  
  423.    if ( !All && !iswild( fpattern ) && !isdir( fparm ))
  424.      {
  425.     (void)cp( fparent, tparm, fpattern );
  426.         exit( NULL );
  427.      }
  428.  
  429.    /*--- For "All" option, don't search the "to" directory --- */
  430.  
  431.    fileptr = (struct FileInfoBlock *)
  432.     AllocMem( (long)sizeof(struct FileInfoBlock), MEMF_CHIP);
  433.  
  434.    strcpy( dontSearch, tparm );
  435.    if ( dontSearch[0] == '\0' )
  436.      {
  437.     dirlock = Lock("", ACCESS_READ);
  438.     if ( dirlock )
  439.        {
  440.         (void)Examine( dirlock, fileptr );
  441.         strcpy( dontSearch, fileptr->fib_FileName );
  442.         UnLock( dirlock );
  443.        }   
  444.      }
  445.  
  446.    initstack();
  447.    push( "" );
  448.    if ( fpattern[0] == '\0' )
  449.       strcpy( fpattern, "#?" );
  450.    if ( CmplPat( fpattern, aux ) == 0 )
  451.      {
  452.     msg("Bad regular expression pattern: %s.\n", fpattern);
  453.     goto all_done;
  454.      }
  455.  
  456.    while( !isempty() )
  457.      {
  458.     pop( relpath );
  459.     (void)makepath( fpath, fparent, relpath );
  460.     (void)makepath( tpath, tparm, relpath );
  461.  
  462.     if ( All && !isdir(tpath) )
  463.        {
  464.         if ( (dirlock = CreateDir( tpath )) == NULL )
  465.            {
  466.             msg( "Can't create %s \n", tpath );
  467.             continue;
  468.            }
  469.         else
  470.            {
  471.             msg("%s ... [created]\n", tpath);
  472.             UnLock( dirlock );
  473.            }
  474.        }
  475.  
  476.     if ( (dirlock = Lock( fpath, ACCESS_READ )) == NULL
  477.       || !Examine( dirlock, fileptr) )
  478.        {
  479.         msg( "Can't find directory %s\n", fpath );
  480.         if ( dirlock )
  481.            UnLock( dirlock );
  482.         goto all_done;
  483.        }
  484.  
  485.     while ( ExNext( dirlock, fileptr ) )
  486.        {
  487.         if ( fileptr->fib_DirEntryType > 0 )
  488.           {
  489.             if ( All && strcmp( dontSearch, fileptr->fib_FileName) )
  490.               push( makepath( junk, relpath, fileptr->fib_FileName ) );
  491.           }
  492.         else if (Match( fpattern, aux, fileptr->fib_FileName ) )
  493.           {
  494.             if ( Chk_Abort() || cp( fpath, tpath, fileptr->fib_FileName ) )
  495.                {
  496.               UnLock( dirlock );
  497.               goto all_done;
  498.                }
  499.           }
  500.        }
  501.     UnLock( dirlock );
  502.      }
  503. all_done:
  504.    FreeMem( fileptr, (long)sizeof(struct FileInfoBlock));
  505.    exit(NULL);
  506. }
  507.